1   /*
2    * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.
8    *
9    * This code is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12   * version 2 for more details (a copy is included in the LICENSE file that
13   * accompanied this code).
14   *
15   * You should have received a copy of the GNU General Public License version
16   * 2 along with this work; if not, write to the Free Software Foundation,
17   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18   *
19   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20   * or visit www.oracle.com if you need additional information or have any
21   * questions.
22   */
23  
24  /*
25   * @test
26   * @bug 6908131
27   * @summary Check for correct implementation of Math.ceil and Math.floor
28   */
29  
30  import sun.misc.FpUtils;
31  import sun.misc.DoubleConsts;
32  
33  public class CeilAndFloorTests {
34      private static int testCeilCase(double input, double expected) {
35          int failures = 0;
36          failures += Tests.test("Math.ceil",  input, Math.ceil(input),   expected);
37          failures += Tests.test("StrictMath.ceil",  input, StrictMath.ceil(input), expected);
38          return failures;
39      }
40  
41      private static int testFloorCase(double input, double expected) {
42          int failures = 0;
43          failures += Tests.test("Math.floor",  input, Math.floor(input),   expected);
44          failures += Tests.test("StrictMath.floor",  input, StrictMath.floor(input), expected);
45          return failures;
46      }
47  
48      private static int nearIntegerTests() {
49          int failures = 0;
50  
51          double [] fixedPoints = {
52              -0.0,
53               0.0,
54              -1.0,
55               1.0,
56              -0x1.0p52,
57               0x1.0p52,
58              -Double.MAX_VALUE,
59               Double.MAX_VALUE,
60               Double.NEGATIVE_INFINITY,
61               Double.POSITIVE_INFINITY,
62               Double.NaN,
63          };
64  
65          for(double fixedPoint : fixedPoints) {
66              failures += testCeilCase(fixedPoint, fixedPoint);
67              failures += testFloorCase(fixedPoint, fixedPoint);
68          }
69  
70          for(int i = Double.MIN_EXPONENT; i <= Double.MAX_EXPONENT; i++) {
71              double powerOfTwo   = Math.scalb(1.0, i);
72              double neighborDown = FpUtils.nextDown(powerOfTwo);
73              double neighborUp   = Math.nextUp(powerOfTwo);
74  
75              if (i < 0) {
76                  failures += testCeilCase( powerOfTwo,  1.0);
77                  failures += testCeilCase(-powerOfTwo, -0.0);
78  
79                  failures += testFloorCase( powerOfTwo,  0.0);
80                  failures += testFloorCase(-powerOfTwo, -1.0);
81  
82                  failures += testCeilCase( neighborDown, 1.0);
83                  failures += testCeilCase(-neighborDown, -0.0);
84  
85                  failures += testFloorCase( neighborUp,  0.0);
86                  failures += testFloorCase(-neighborUp, -1.0);
87              } else {
88                  failures += testCeilCase(powerOfTwo, powerOfTwo);
89                  failures += testFloorCase(powerOfTwo, powerOfTwo);
90  
91                  if (neighborDown==Math.rint(neighborDown)) {
92                      failures += testCeilCase( neighborDown,  neighborDown);
93                      failures += testCeilCase(-neighborDown, -neighborDown);
94  
95                      failures += testFloorCase( neighborDown, neighborDown);
96                      failures += testFloorCase(-neighborDown,-neighborDown);
97                  } else {
98                      failures += testCeilCase( neighborDown, powerOfTwo);
99                      failures += testFloorCase(-neighborDown, -powerOfTwo);
100                 }
101 
102                 if (neighborUp==Math.rint(neighborUp)) {
103                     failures += testCeilCase(neighborUp, neighborUp);
104                     failures += testCeilCase(-neighborUp, -neighborUp);
105 
106                     failures += testFloorCase(neighborUp, neighborUp);
107                     failures += testFloorCase(-neighborUp, -neighborUp);
108                 } else {
109                     failures += testFloorCase(neighborUp, powerOfTwo);
110                     failures += testCeilCase(-neighborUp, -powerOfTwo);
111                 }
112             }
113         }
114 
115         for(int i = -(0x10000); i <= 0x10000; i++) {
116             double d = (double) i;
117             double neighborDown = FpUtils.nextDown(d);
118             double neighborUp   = Math.nextUp(d);
119 
120             failures += testCeilCase( d, d);
121             failures += testCeilCase(-d, -d);
122 
123             failures += testFloorCase( d, d);
124             failures += testFloorCase(-d, -d);
125 
126             if (Math.abs(d) > 1.0) {
127                 failures += testCeilCase( neighborDown, d);
128                 failures += testCeilCase(-neighborDown, -d+1);
129 
130                 failures += testFloorCase( neighborUp, d);
131                 failures += testFloorCase(-neighborUp, -d-1);
132             }
133         }
134 
135         return failures;
136     }
137 
138     public static int roundingTests() {
139         int failures = 0;
140         double [][] testCases = {
141             { Double.MIN_VALUE,                           1.0},
142             {-Double.MIN_VALUE,                          -0.0},
143             { FpUtils.nextDown(DoubleConsts.MIN_NORMAL),  1.0},
144             {-FpUtils.nextDown(DoubleConsts.MIN_NORMAL), -0.0},
145             { DoubleConsts.MIN_NORMAL,                    1.0},
146             {-DoubleConsts.MIN_NORMAL,                   -0.0},
147 
148             { 0.1,                                        1.0},
149             {-0.1,                                       -0.0},
150 
151             { 0.5,                                        1.0},
152             {-0.5,                                       -0.0},
153 
154             { 1.5,                                        2.0},
155             {-1.5,                                       -1.0},
156 
157             { 2.5,                                        3.0},
158             {-2.5,                                       -2.0},
159 
160             { FpUtils.nextDown(1.0),                      1.0},
161             { FpUtils.nextDown(-1.0),                    -1.0},
162 
163             { Math.nextUp(1.0),                           2.0},
164             { Math.nextUp(-1.0),                         -0.0},
165 
166             { 0x1.0p51,                                 0x1.0p51},
167             {-0x1.0p51,                                -0x1.0p51},
168 
169             { FpUtils.nextDown(0x1.0p51),               0x1.0p51},
170             {-Math.nextUp(0x1.0p51),                   -0x1.0p51},
171 
172             { Math.nextUp(0x1.0p51),                    0x1.0p51+1},
173             {-FpUtils.nextDown(0x1.0p51),              -0x1.0p51+1},
174 
175             { FpUtils.nextDown(0x1.0p52),               0x1.0p52},
176             {-Math.nextUp(0x1.0p52),                   -0x1.0p52-1.0},
177 
178             { Math.nextUp(0x1.0p52),                    0x1.0p52+1.0},
179             {-FpUtils.nextDown(0x1.0p52),              -0x1.0p52+1.0},
180         };
181 
182         for(double[] testCase : testCases) {
183             failures += testCeilCase(testCase[0], testCase[1]);
184             failures += testFloorCase(-testCase[0], -testCase[1]);
185         }
186         return failures;
187     }
188 
189     public static void main(String... args) {
190         int failures = 0;
191 
192         failures += nearIntegerTests();
193         failures += roundingTests();
194 
195         if (failures > 0) {
196             System.err.println("Testing {Math, StrictMath}.ceil incurred "
197                                + failures + " failures.");
198             throw new RuntimeException();
199         }
200     }
201 }